﻿package
{
	import entities.MicroGZMCamera;
	import entities.MicroGZMCar;
	import entities.MicroGZMMap;

	import com.adobe.utils.AGALMiniAssembler;

	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Program3D;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;

	
	public class Main extends Sprite
	{
		private const SWF_WIDTH:Number = 640;
		private const SWF_HEIGHT:Number = 480;
		private const MOVE_SPEED:Number = 0.1;
	
		private var timer:MicroGZMTimer;
		private var input:MicroGZMInput;
			
		private var cam:MicroGZMCamera;
//		private var player:MicroGZMPlayer;
		private var car:MicroGZMCar;
		private var plane:MicroGZMMap;
		
		private var context3D:Context3D;
		private var shaderProgram1:Program3D;
		
//		private var projectionmatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
		private var viewmatrix:Matrix3D = new Matrix3D();
		
		public function Main() 
		{
			addEventListener( Event.ADDED_TO_STAGE, init );
		}
		
		private function init( e:Event = null ):void 
		{
			removeEventListener( Event.ADDED_TO_STAGE, init );
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
	
			stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, onContext3DCreate );
			stage.stage3Ds[0].requestContext3D();
		}
		
		private function initShaders():void
		{
			var vertexShaderAssembler:AGALMiniAssembler = new AGALMiniAssembler();
			vertexShaderAssembler.assemble
			( 
				Context3DProgramType.VERTEX,
				// 4x4 matrix multiply to get camera angle	
				"m44 op, va0, vc0\n" +
				// tell fragment shader about XYZ
				"mov v0, va0\n" +
				// tell fragment shader about UV
				"mov v1, va1\n" +
				// tell fragment shader about RGBA
				"mov v2, va2"
			);			
			
			// textured using UV coordinates
			var fragmentShaderAssembler1:AGALMiniAssembler 
				= new AGALMiniAssembler();
			fragmentShaderAssembler1.assemble
			( 
				Context3DProgramType.FRAGMENT,	
				// grab the texture color from texture 0 
				// and uv coordinates from varying register 1
				// and store the interpolated value in ft0
				"tex ft0, v1, fs0 <2d,linear,repeat,miplinear>\n"+
				// move this value to the output color
				"mov oc, ft0\n"
			);
			
			// combine shaders into a program which we then upload to the GPU
			shaderProgram1 = context3D.createProgram();
			shaderProgram1.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler1.agalcode );
		}
		
		private function onContext3DCreate(event:Event):void 
		{
			if (hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME,enterFrame);
			
			var t:Stage3D = event.target as Stage3D;					
			context3D = t.context3D; 	
		
			if (context3D == null) 
			{
				trace('ERROR: no context3D - video driver problem?');
				return;
			}
			
			context3D.enableErrorChecking = true;
			
			context3D.configureBackBuffer( SWF_WIDTH, SWF_HEIGHT, 2, true);
		
			initShaders();
		
			initData();
			
			addEventListener( Event.ENTER_FRAME, enterFrame );
		}
		
		private function initData():void 
		{
			timer = new MicroGZMTimer(heartbeat);
			input = new MicroGZMInput(stage);
			
//			player = new MicroGZMPlayer( context3D, shaderProgram1 );
			car = new MicroGZMCar( context3D, shaderProgram1 );
			
			cam = new MicroGZMCamera( context3D );
//			car.globalTransform = false;
			cam.y = car.height + 5;
			cam.z = car.depth + 2;
			cam.rotationDegreesX = -15;
			
			plane = new MicroGZMMap( context3D, shaderProgram1 );
			
		}
		
		private function renderScene():void 
		{
			viewmatrix.identity();
			viewmatrix.append( cam.transform );
			viewmatrix.invert();
			viewmatrix.appendRotation( 15, Vector3D.X_AXIS );
			
			viewmatrix.appendRotation(input.cameraAngleX, Vector3D.X_AXIS);
			viewmatrix.appendRotation(input.cameraAngleY, Vector3D.Y_AXIS);
			viewmatrix.appendRotation(input.cameraAngleZ, Vector3D.Z_AXIS);
			
			car.render( viewmatrix, cam.projectionmatrix );
			plane.render( viewmatrix, cam.projectionmatrix );
		}
		
		private function gameStep(frameMs:uint):void 
		{
			var moveAmount:Number = MOVE_SPEED * frameMs;
			
//			if( input.pressing.up ) car.z -= moveAmount;
//			if( input.pressing.down ) car.z += moveAmount;
//			if( input.pressing.left ) car.rotationDegreesY -= moveAmount;
//			if( input.pressing.right ) car.rotationDegreesY += moveAmount;
			
			
			if( input.pressing.up ) car.moveForward( moveAmount );
			if( input.pressing.down ) car.moveBackward( moveAmount );
			if( input.pressing.left ) car.rotationDegreesY+=5;
			if( input.pressing.right ) car.rotationDegreesY-=5;
			
//			trace(car.rotationDegreesY + " :y")
//			
//			cam.x = car.x
//			cam.z = car.z + (car.depth + 2);
//			
//			cam.rotationDegreesY = car.rotationDegreesY;

		}
		
		private function heartbeat():void
		{
		}
		
		private function enterFrame(e:Event):void 
		{
			context3D.clear(0,0,0);
			
			timer.tick();
			
			gameStep(timer.frameMs);
		
			renderScene();
			
			context3D.present();
		}
	}
} 
